import { Injectable } from '@angular/core';

import { ValidationType } from './model/validation.definition';
import { LoggerService, LoggerInfo } from '../logger/logger.service';

Injectable()
export class ValidationService {
    logger: LoggerService;
    constructor() {
        this.logger = new LoggerService();
    }

    public checkingAllPass(groups: any[], ...items): boolean {
        let result: boolean = false;
        for (let type of groups) {
            if (typeof type == "number") {
                result = this.FindMethod(type)(true, undefined, items);
            } else {
                let mType: number = type.type;
                let mOption: any = type.option;
                let mInput: any = type.input;
                result = this.FindMethod(mType)(mOption, mInput, items);
            }
            if (!result)
                break;
        }
        return result;
    }

    public checkingHasPass(groups: any[], ...items): boolean {
        let result: boolean = false;
        for (let type of groups) {
            if (typeof type == "number") {
                result = this.FindMethod(type)(true, undefined, items);
            } else {
                let mType: number = type.Type;
                let mOption: any = type.Option;
                let mInput: any = type.Input;
                result = this.FindMethod(mType)(mOption, mInput, items);
            }
            if (result)
                break;
        }
        return result;
    }

    private notNull(flag: any, input: any, ...items): boolean {
        let result: boolean = true;
        for (let item of items[0]) { //must add 0 index, cause rest parameter will convert to array as pass it to other function
            result = (item == undefined || item == null) ? false : true;
            if (!result)
                break;
        }
        if (flag)
            return result == true;
        else
            return result == false;
    }

    private notEmpty(flag: any, input: any, ...items): boolean {
        let result: boolean = true;
        for (let item of items[0]) {
            result = (item == undefined || item.length == 0 || (typeof item == "string" && item.trim() == "")) ? false : true;
            if (!result)
                break;
        }
        if (flag)
            return result == true; //true: all items are not empty, false: at least 1 item is empty
        else
            return result == false; //true: at least 1 item is empty, false: all items are empty
    }

    private noDanCharacter(flag: any, input: any, ...items): boolean {
        let result: boolean = true;
        let re = /[@#\$%\^&\*\'\"\=]+/g;
        for (let item of items[0]) {
            result = (typeof item == "string" && re.test(item)) ? false : true;
            if (!result)
                break;
        }
        if (flag)
            return result == true; //true: all items dont include dc, false: at least 1 item include dc
        else
            return result == false; //true: at least 1 item include dc,  false: all item include dc
    }

    private lengthScope(flag: any, input: any, ...items): boolean {
        let result: boolean = true;
        if (typeof input === "string") {
            let orArray: string[] = input.split('or');
            let orResult: boolean = false;
            for (let orItem of orArray) {
                let andArray: string[] = orItem.split('and');
                let andResult: boolean = true;
                for (let andItem of andArray) {
                    andResult = andResult && ValidationService.singleScope(andItem, ...items);
                }
                orResult = orResult || andResult;
            }
            result = orResult;
        }
        else {
            this.logger.warning(new LoggerInfo("validation/validation.service", "method:LengthScope, input item is not string type", ""));
            result = false;
        }
        return result;
    }

    private FindMethod(type: ValidationType): Function {
        switch (type) {
            case ValidationType.NotNull:
                return this.notNull;
            case ValidationType.NotEmpty:
                return this.notEmpty;
            case ValidationType.NoDanCharacter:
                return this.noDanCharacter;
            case ValidationType.LengthScope:
                return this.lengthScope;
            default:
                return undefined;
        }
    }

    private static singleScope(input: string, ...items): boolean {
        let result: boolean = true;
        let array: string[] = input.split(',');
        let min: string = array[0].trim();
        let max: string = array[1].trim();
        let minCharacter: string = min.substring(0, 1);
        let maxCharacter: string = max.substring(max.length - 1);
        let minValue: number = (min.substring(1, min.length) == "~") ? Number.MIN_VALUE : parseFloat(min.substring(1, min.length));
        let maxValue: number = (max.substring(0, max.length - 1) == "~") ? Number.MAX_VALUE : parseFloat(max.substring(0, max.length - 1));
        for (let item of items[0]) {
            let minResult: boolean = true;
            let maxResult: boolean = true;
            if (minCharacter == "(") {
                minResult = (item.length > minValue) ? true : false;
            } else if (minCharacter == "[") {
                minResult = (item.length >= minValue) ? true : false;
            } else {
                minResult = false;
            }
            if (maxCharacter == ")") {
                maxResult = (item.length < maxValue) ? true : false;
            } else if (maxCharacter == "]") {
                maxResult = (item.length <= maxValue) ? true : false;
            } else {
                maxResult = false;
            }
            result = minResult && maxResult;
            if (!result)
                break;
        }
        return result;
    }
}